//
//  YuanXinKeyChainManager.m
//  YuanXinKit
//
//  Created by wangxue on 16/10/11.
//  Copyright © 2016年 晏德智. All rights reserved.
//

#import "YuanXinKeyChainManager.h"
#import <Security/Security.h>
/*
#import <React/RCTConvert.h>
#import <React/RCTBridge.h>
#import <React/RCTUtils.h>
 */

@implementation YuanXinKeyChainManager

@synthesize bridge = _bridge;

RCT_EXPORT_MODULE();

- (dispatch_queue_t)methodQueue
{
    return dispatch_get_main_queue();
}

//增  service->标识  username->
RCT_EXPORT_METHOD(savefromService:(NSString*)service data:(id)data userName:(NSString *)username callback:(RCTPromiseResolveBlock)callback){
    
    if(service == nil) {
        service = [[NSBundle mainBundle] bundleIdentifier];
    }
    //查询条件参数
    NSDictionary* dict = [NSDictionary dictionaryWithObjectsAndKeys:(__bridge id)(kSecClassGenericPassword),  kSecClass, service, kSecAttrService, kCFBooleanTrue, kSecReturnAttributes, nil];
    
    //删除旧的
    OSStatus osStatus = SecItemDelete((__bridge CFDictionaryRef) dict);
    
    //增加条件参数
    dict = [NSDictionary dictionaryWithObjectsAndKeys:(__bridge id)(kSecClassGenericPassword), kSecClass, service, kSecAttrService, (id)[NSKeyedArchiver archivedDataWithRootObject:data], kSecValueData, username, kSecAttrAccount, nil];
    //存
    osStatus = SecItemAdd((__bridge CFDictionaryRef) dict, NULL);
    
    //
    if (osStatus != noErr && osStatus != errSecItemNotFound) {
        NSError *error = [NSError errorWithDomain:NSOSStatusErrorDomain code:osStatus userInfo:nil];
        return callback(@[makeError(error)]);
    }
    if (callback) {
        callback(@[[NSNull null]]);
    }
    
}

//查return @{@"kSecAttrAccount":@"",@"kSecValueData":}
RCT_EXPORT_METHOD(KeychainQuery:(NSString*)service callback:(RCTPromiseResolveBlock)callback){
    
    if(service == nil) {
        service = [[NSBundle mainBundle] bundleIdentifier];
    }
    
    //查询参数
    NSMutableDictionary* dict = [NSMutableDictionary dictionaryWithObjectsAndKeys:(__bridge id)(kSecClassGenericPassword), kSecClass, service, kSecAttrService, kCFBooleanTrue, kSecReturnAttributes, kCFBooleanTrue, kSecReturnData, nil];
    
    //
    NSDictionary* found = nil;
    CFTypeRef foundTypeRef = NULL;
    OSStatus osStatus = SecItemCopyMatching((__bridge CFDictionaryRef) dict, (CFTypeRef*)&foundTypeRef);
    
    if (osStatus != noErr && osStatus != errSecItemNotFound) {
        NSError *error = [NSError errorWithDomain:NSOSStatusErrorDomain code:osStatus userInfo:nil];
        return callback(@[makeError(error)]);
    }
    
    found = (__bridge NSDictionary*)(foundTypeRef);
    if (!found) {
        return callback(@[[NSNull null]]);
    }
    
    // Found
    NSString* username = (NSString*) [found objectForKey:(__bridge id)(kSecAttrAccount)];
    id data = nil;
    @try {
        data  = [NSKeyedUnarchiver unarchiveObjectWithData:[found objectForKey:(__bridge id)(kSecValueData)]];
    } @catch (NSException *e) {
        NSLog(@"Unarchive of %@ failed: %@", service, e);
    } @finally {
    }
    
    NSMutableDictionary *result = [NSMutableDictionary dictionary];
    if(username){
        [result setObject:username forKey:@"kSecAttrAccount"];
    }
    if (data){
        [result setObject:data forKey:@"kSecValueData"];
    }
    if (callback) {
        callback(result);
    }
}

//删 service->标识
RCT_EXPORT_METHOD(resetGenericPasswordForService:(NSString*)service callback:(RCTPromiseResolveBlock)callback){
    if(service == nil) {
        service = [[NSBundle mainBundle] bundleIdentifier];
    }
    
    //
    NSMutableDictionary* dict = [NSMutableDictionary dictionaryWithObjectsAndKeys:(__bridge id)(kSecClassGenericPassword), kSecClass, service, kSecAttrService, kCFBooleanTrue, kSecReturnAttributes, kCFBooleanTrue, kSecReturnData, nil];
    
    //
    OSStatus osStatus = SecItemDelete((__bridge CFDictionaryRef) dict);
    if (osStatus != noErr && osStatus != errSecItemNotFound) {
        NSError *error = [NSError errorWithDomain:NSOSStatusErrorDomain code:osStatus userInfo:nil];
        return callback(@[makeError(error)]);
    }
    
    if (callback) {
        
        callback(@[[NSNull null]]);
        
    }
    
}

#pragma mark - methods

// 存
+ (BOOL)savefromService:(NSString *)userName Data:(id)data {
    
    NSString  *service = [[NSBundle mainBundle] bundleIdentifier];
    
    //查询条件参数
    NSDictionary* dict = [NSDictionary dictionaryWithObjectsAndKeys:(__bridge id)(kSecClassGenericPassword),  kSecClass, service, kSecAttrService, kCFBooleanTrue, kSecReturnAttributes, nil];
    
    //删除旧的
    OSStatus osStatus = SecItemDelete((__bridge CFDictionaryRef) dict);
    
    //增加条件参数
    dict = [NSDictionary dictionaryWithObjectsAndKeys:(__bridge id)(kSecClassGenericPassword), kSecClass, service, kSecAttrService, (id)[NSKeyedArchiver archivedDataWithRootObject:data], kSecValueData, userName, kSecAttrAccount, nil];
    //存
    osStatus = SecItemAdd((__bridge CFDictionaryRef) dict, NULL);
    
    //
    if (osStatus != noErr && osStatus != errSecItemNotFound) {
        NSError *error = [NSError errorWithDomain:NSOSStatusErrorDomain code:osStatus userInfo:nil];
        NSLog(@"存储keyChain失败%@", error.description);
        
        return NO;
    }else {
        
        return YES;
    }
    
}

//查
+ (id)keyChainQuery {
    
    NSString  *service  = [[NSBundle mainBundle] bundleIdentifier];
    
    
    //查询参数
    NSMutableDictionary* dict = [NSMutableDictionary dictionaryWithObjectsAndKeys:(__bridge id)(kSecClassGenericPassword), kSecClass, service, kSecAttrService, kCFBooleanTrue, kSecReturnAttributes, kCFBooleanTrue, kSecReturnData, nil];
    
    //
    NSDictionary* found = nil;
    CFTypeRef foundTypeRef = NULL;
    OSStatus osStatus = SecItemCopyMatching((__bridge CFDictionaryRef) dict, (CFTypeRef*)&foundTypeRef);
    
    if (osStatus != noErr && osStatus != errSecItemNotFound) {
        NSError *error = [NSError errorWithDomain:NSOSStatusErrorDomain code:osStatus userInfo:nil];
        NSLog(@"查询keyChain失败%@",error.description);
        return nil;
    }
    
    found = (__bridge NSDictionary*)(foundTypeRef);
    if (!found) {
        
        NSLog(@"查询keyChain没有结果");
        
        return nil;
    }
    
    // Found
    NSString* username = (NSString*) [found objectForKey:(__bridge id)(kSecAttrAccount)];
    id data = nil;
    @try {
        data  = [NSKeyedUnarchiver unarchiveObjectWithData:[found objectForKey:(__bridge id)(kSecValueData)]];
    } @catch (NSException *e) {
        NSLog(@"Unarchive of %@ failed: %@", service, e);
    } @finally {
    }
    
    NSMutableDictionary *result = [NSMutableDictionary dictionary];
    if(username){
        [result setObject:username forKey:@"userName"];
    }
    if (data){
        [result setObject:data forKey:@"userData"];
    }
    
    return result;
}

//删
+ (BOOL)resetKeyChain {
    NSString *service = [[NSBundle mainBundle] bundleIdentifier];
    //
    NSMutableDictionary* dict = [NSMutableDictionary dictionaryWithObjectsAndKeys:(__bridge id)(kSecClassGenericPassword), kSecClass, service, kSecAttrService, kCFBooleanTrue, kSecReturnAttributes, kCFBooleanTrue, kSecReturnData, nil];
    //
    OSStatus osStatus = SecItemDelete((__bridge CFDictionaryRef) dict);
    if (osStatus != noErr && osStatus != errSecItemNotFound) {
        NSError *error = [NSError errorWithDomain:NSOSStatusErrorDomain code:osStatus userInfo:nil];
        NSLog(@"删除keychain失败%@",error.description);
        return NO;
    }
    
    return YES;
    
}

// Messages from the comments in <Security/SecBase.h>
NSString *messageForError(NSError *error)
{
    switch (error.code) {
        case errSecUnimplemented:
            return @"Function or operation not implemented.";
            
        case errSecIO:
            return @"I/O error.";
            
        case errSecOpWr:
            return @"File already open with with write permission.";
            
        case errSecParam:
            return @"One or more parameters passed to a function where not valid.";
            
        case errSecAllocate:
            return @"Failed to allocate memory.";
            
        case errSecUserCanceled:
            return @"User canceled the operation.";
            
        case errSecBadReq:
            return @"Bad parameter or invalid state for operation.";
            
        case errSecNotAvailable:
            return @"No keychain is available. You may need to restart your computer.";
            
        case errSecDuplicateItem:
            return @"The specified item already exists in the keychain.";
            
        case errSecItemNotFound:
            return @"The specified item could not be found in the keychain.";
            
        case errSecInteractionNotAllowed:
            return @"User interaction is not allowed.";
            
        case errSecDecode:
            return @"Unable to decode the provided data.";
            
        case errSecAuthFailed:
            return @"The user name or passphrase you entered is not correct.";
            
        default:
            return error.localizedDescription;
    }
}

NSDictionary * makeError(NSError *error)
{
    return RCTMakeAndLogError(messageForError(error), nil, [error dictionaryWithValuesForKeys:@[@"domain", @"code"]]);
}

@end
